package com.ruoyi.web.controller.app.user;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.core.collection.CollUtil;
import com.ruoyi.app.domain.AppUserCode;
import com.ruoyi.app.domain.bo.AppUserBo;
import com.ruoyi.app.domain.bo.AppUserCodeBo;
import com.ruoyi.app.domain.vo.AppUserCodeVo;
import com.ruoyi.app.domain.vo.AppUserVo;
import com.ruoyi.app.service.IAppUserCodeService;
import com.ruoyi.app.service.IAppUserService;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.utils.OrderNumUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.web.service.RealNameService;
import com.ruoyi.web.service.pay.AlipayCertService;
import com.ruoyi.web.service.pay.AlipayUtil;
import com.ruoyi.web.service.pay.WxPayCertService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.jdom2.JDOMException;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;

/**
 * 实名认证
 *
 * @author ruoyi
 * @date 2025-08-08
 */
@Slf4j
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/app/userCode")
public class AppUserCodeController extends BaseController {


    // 包含大小写字母和数字的字符池
    private static final String CHAR_POOL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    private static final SecureRandom random = new SecureRandom();

    private final IAppUserService appUserService;
    private final ISysConfigService sysConfigService;
    private final IAppUserCodeService appUserCodeService;


    /**
     * 新增实名认证订单
     */

    @PostMapping("/create")
    public R<?> create(@Validated(AddGroup.class) AppUserCodeBo bo) {
        Long id = getUserId();
        AppUserVo userVo = appUserService.queryById(id);
        //查询是否存在已支付的订单
        List<AppUserCode> appUserCodes  = appUserCodeService.selUserCodeList(id);


        if (ObjectUtils.isNotEmpty(userVo) && StringUtils.isNotBlank(userVo.getCode())) {
            return R.fail("实名认证已通过！");
        }

        if (CollUtil.isNotEmpty(appUserCodes)){
            for (AppUserCode appUserCode : appUserCodes) {
                if (appUserCode.getStatus().equals(Constants.FAIL)){
                    System.err.println(appUserCode.getStatus());
                    //查询身份证号是否 以及姓名是否 和之前匹配 不匹配则需要修改
                    appUserCode.setCode(bo.getCode());
                    appUserCode.setCodeName(bo.getCodeName());
                    appUserCodeService.updateCodeData(appUserCode);
                    AppUserBo appUserBo = new AppUserBo();
                    appUserBo.setId(appUserCode.getUserId());
                    appUserBo.setCode(appUserCode.getCode());
                    appUserService.updateByBo(appUserBo);
                    bo.setUserId(id);
                    bo.setOrderNo(appUserCode.getOrderNo());
                    bo.setStatus(Constants.FAIL);
                    bo.setCodePrice(appUserCode.getCodePrice());
                    return R.ok(bo);
                }
            }
        }
        BigDecimal price = new BigDecimal(sysConfigService.selectConfigByKey("app.real.price"));
        String orderNo = OrderNumUtils.getInstance().generateOrderNo();
        bo.setUserId(id);
        bo.setOrderNo(orderNo);
        bo.setCodePrice(price);
        if (price.compareTo(BigDecimal.ZERO) <= 0) {
            bo.setStatus(Constants.FAIL);
        } else {
            bo.setStatus(Constants.SUCCESS);
        }
        bo.setVerifyStatus(Constants.SUCCESS);
        return appUserCodeService.insertByBo(bo) ? R.ok(bo) : R.fail();
    }


    /**
     * 订单支付签名
     */

    @PostMapping("/sign")
    public R<?> sign(@RequestParam(name = "orderNo") String orderNo, @RequestParam(name = "payType") Integer payType, HttpServletRequest request) throws Exception {
        Long id = getUserId();
        Map<String, String> params = new HashMap<>(2);
        AppUserCodeVo serCodeVo = appUserCodeService.queryByOrderNo(orderNo);
        if (ObjectUtils.isEmpty(serCodeVo) || !serCodeVo.getUserId().equals(id)) {
            return R.fail("订单号错误！");
        }
        if (StringUtils.equals(serCodeVo.getStatus(), Constants.FAIL)) {
            return R.fail("订单已付款！");
        }
        Map<String, String> map = new LinkedHashMap<>();
        params.put("body", "全能帮手");
        params.put("subject", "全能帮手");
        params.put("tradeNo", orderNo);
        params.put("amount", serCodeVo.getCodePrice().toPlainString());
        if (1 == payType) {
            params.put("notifyUrl", Constants.SERVER + "/app/userCode/aliPayCallBack");
            String sign = AlipayCertService.creatOrder(params);
            map.put("sign", sign);
            return R.ok(map);
        }
        if (2 == payType) {
            params.put("attach", null);
            params.put("notifyUrl", Constants.SERVER + "/app/userCode/wxPayCallBack");
            Map<String, String> signParam = WxPayCertService.createAppPayment(params, request);
            return R.ok(signParam);
        }
        return R.fail("支付签名失败！");
    }


    /**
     * 获取实名认证签名
     */

    @PostMapping("/getFaceId")
    public R<?> getFaceId(@RequestParam(name = "orderNo") String orderNo) {
        Long id = getUserId();
        AppUserCodeVo serCodeVo = appUserCodeService.queryByOrderNo(orderNo);
        if (ObjectUtils.isEmpty(serCodeVo) || !serCodeVo.getUserId().equals(id)) {
            return R.fail("订单号错误！");
        }
        if (StringUtils.equals(serCodeVo.getStatus(), Constants.SUCCESS)) {
            return R.fail("订单未付款！");
        }
//        if (StringUtils.equals(serCodeVo.getVerifyStatus(), Constants.FAIL)) {
//            return R.fail("本次实名认证已使用，请重新支付！");
//        }
        String nonce = generate(32);
        String txUserId = "userID" + id;
        HashMap<String, String> map = RealNameService.checkName(serCodeVo.getCodeName(), serCodeVo.getCode(), txUserId, serCodeVo.getOrderNo(), nonce);
        if (map.isEmpty()) {
            return R.fail("姓名或身份证号不正确！");
        } else {
            AppUserCodeBo userCodeBo = new AppUserCodeBo();
            userCodeBo.setVerifyStatus(Constants.FAIL);
            userCodeBo.setCodeId(serCodeVo.getCodeId());
            appUserCodeService.updateByBo(userCodeBo);
        }
        serCodeVo.setNonce(nonce);
        serCodeVo.setTxUserId(txUserId);
        serCodeVo.setFaceId(map.get("faceId"));
        serCodeVo.setOpenApiSign(map.get("openApiSign"));
        return R.ok(serCodeVo);
    }

    /**
     * 实名认证支付宝回调
     * 证书模式验证
     *
     * @param request 回调参数
     * @return
     */
    @SaIgnore
    @PostMapping("aliPayCallBack")
    public String aliPayCallBack(HttpServletRequest request) throws Exception {
        Map<String, String[]> parameterMap = request.getParameterMap();
        StringBuilder notifyBuild = new StringBuilder("/****************************** alipay notify ******************************/\n");
        parameterMap.forEach((key, value) -> notifyBuild.append(key + "=" + value[0] + "\n"));
        log.info(notifyBuild.toString());
        log.info("通知回调：实名认证支付宝回调日志信息：" + request.getParameterMap().toString());
        if (AlipayUtil.rsaCheckV1(request)) {
            String lCharset = "ISO-8859-1";
            String rCharset = "UTF-8";
            String tradeStatus = new String(request.getParameter("trade_status").getBytes(lCharset), rCharset);
            // 商户订单号
            String outTradeNo = new String(request.getParameter("out_trade_no").getBytes(lCharset), rCharset);
            // 支付宝交易号
            String tradeNo = new String(request.getParameter("trade_no").getBytes(lCharset), rCharset);
            if ("TRADE_SUCCESS".equalsIgnoreCase(tradeStatus)) {
                AppUserCodeVo codeVo = appUserCodeService.queryByOrderNo(outTradeNo);
                if (codeVo != null && codeVo.getStatus().equals(Constants.SUCCESS)) {
                    AppUserCodeBo userCodeBo = new AppUserCodeBo();
                    userCodeBo.setStatus(Constants.FAIL);
                    userCodeBo.setCodeId(codeVo.getCodeId());
                    appUserCodeService.updateByBo(userCodeBo);
                    log.info("实名认证支付宝支付回调成功");
                    return "success";
                }
            }
        }
        return "failure";
    }


    /**
     * 实名认证微信回调
     * 证书模式验证
     *
     * @param request 回调参数
     * @return String
     */
    @SaIgnore
    @PostMapping("/wxPayCallBack")
    public String wxPayCallBack(HttpServletRequest request) throws IOException {
        log.info("实名认证微信支付回调开始");
        String resXml = "<xml><return_code>FAIL</return_code><return_msg>OK</return_msg></xml>";
        InputStream inStream = request.getInputStream();
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outSteam.write(buffer, 0, len);
        }
        String resultxml = new String(outSteam.toByteArray(), "utf-8");
        Map<String, String> params = null;
        try {
            params = WxPayCertService.doXMLParse(resultxml);
        } catch (JDOMException e) {
            e.printStackTrace();
        }
        outSteam.close();
        inStream.close();
        if (WxPayCertService.isTenpaySign(params)) {
            log.info("=================================微信付款回调验证成功=================================");
            // 获取内部订单编号
            String outTradeNo = params.get("out_trade_no");
            String tradeNo = params.get("transaction_id");
            String returnCode = params.get("return_code");
            if ("SUCCESS".equals(returnCode)) {
                AppUserCodeVo codeVo = appUserCodeService.queryByOrderNo(outTradeNo);
                if (codeVo != null && codeVo.getStatus().equals(Constants.SUCCESS)) {
                    AppUserCodeBo userCodeBo = new AppUserCodeBo();
                    userCodeBo.setStatus(Constants.FAIL);
                    userCodeBo.setCodeId(codeVo.getCodeId());
                    appUserCodeService.updateByBo(userCodeBo);
                    log.info("=================================微信支付回调业务处理完毕=================================");
                    return "<xml><return_code>SUCCESS</return_code><return_msg>OK</return_msg></xml>";
                }
            }
        }
        // 支付回调失败
        log.info("=================================实名认证付款回调验证失败=================================");
        return resXml;
    }


    private static String generate(int length) {
        if (length <= 0) throw new IllegalArgumentException("长度必须大于0");
        StringBuilder sb = new StringBuilder(length);
        IntStream.range(0, length).forEach(i -> sb.append(CHAR_POOL.charAt(random.nextInt(CHAR_POOL.length()))));
        return sb.toString();
    }
}
